
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>

#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <linux/types.h>
#include <linux/spi/spidev.h>

#include "myqueue.h"
#include "dbg_cli.h"


int  test_spi( int tlen ) 
{
    int fd;
    int iret;
    struct spi_ioc_transfer mesg[4];
    uint8_t  txdat[4096];
    uint8_t  rxdat[4096];
    
    fd = open( "/dev/spidev0.0", O_RDWR );
    if ( fd < 0 )  {
        printf( "open spidev fail\n" );
        return 1;
    }
    
    
    txdat[0] = 0x03;
    txdat[1] = 0x00;
    txdat[2] = 0x11;
    txdat[3] = 0x22;
    
    memset( mesg, 0, sizeof(struct spi_ioc_transfer) );
    
    mesg[0].tx_buf = (uintptr_t)txdat;
    mesg[0].rx_buf = (uintptr_t)rxdat;
    mesg[0].len = tlen;
    mesg[0].speed_hz = 20000000;
    mesg[0].bits_per_word = 8;
    
 
    iret = ioctl( fd, SPI_IOC_MESSAGE(1), mesg );
    printf( "ret = %d\n", iret );
    
    close(fd);
    return 0;
}



int debug_cmd_spi( void * pctx, int argc, const char **argv )
{
    int iret;
    uint32_t temp;

    if ( argc < 2 )  {
        goto usage;
    }

    iret = debug_str2uint( argv[1], &temp );
    if ( iret != 0 )  {
        printf( "tlen parse fail, %d\n", iret );
        goto usage;
    }

    iret = test_spi( (int)temp );
    return 0;

usage:
    printf( "%s <tlen>\n", argv[0] );
    return 0;
}



int mthrd_proc_uio( int uiofd )
{
    int iret;
    uint32_t  tcnt;

    iret = read( uiofd, &tcnt, 4 );
    if ( iret != 4  )  {
        printf( "read fail, %d\n", iret );
        return 3;
    }
    
    printf( "irq = %u\n", tcnt );
    return 0;
}



int mthrd_proc_cmd( mthrd_ctx_t * pctx )
{
    int iret;
    char * ptr;

    while ( true )  {

        iret = msq_dequeue( pctx->qctx, (void **)&ptr );
        if ( 1 == iret )  {
            return 14;
        }

        if ( 0 != iret )  {
            break;
        }

        // simple process, trim space and tail...
        while ( isspace(*ptr) )  {
            ptr += 1;
        }

        iret = strlen( ptr );
        if ( iret > 0 )  {

            if ( ptr[iret-1] == 0x0A )  {
                ptr[iret-1] = '\0';
                iret = iret - 1;
            }

        }

        if ( iret <= 0 )  {
            // nothing...
            printf( ">> " );
            continue;
        }

        /* proc data */
        // printf( "recv ptr : %p, %d\n", pdat, strlen(pdat) );
        // debug_dump_hex( (uint8_t *)pdat, strlen(pdat) + 1 );
        debug_proc_line( ptr, pctx );
        printf( ">> " );
    }
    
    return 0;
}


int mthrd_run( intptr_t qctx, int uiofd )
{
    mthrd_ctx_t mctx;
    int iret;
    int  num;
    int  aqfd;
    int  epfd;
    struct epoll_event  tevent;
    struct epoll_event  * pevent;
    void * pregs;

    iret = debug_cli_init();
    if ( 0 != iret )  {
        return 2;
    }
    
    debug_add_cmd( "spi", debug_cmd_spi,      NULL );
    

    /* epoll */
    epfd = epoll_create( 5 );
    if ( epfd < 0 )  {
        return 3;
    }

    msq_getefd( qctx, &aqfd );
    tevent.events = EPOLLIN;
    tevent.data.fd = aqfd;
    iret = epoll_ctl( epfd, EPOLL_CTL_ADD, aqfd, &tevent );
    if ( 0 != iret )  {
        return 4;
    }
    
    tevent.events = EPOLLIN;
    tevent.data.fd = uiofd;
    iret = epoll_ctl( epfd, EPOLL_CTL_ADD, uiofd, &tevent );
    if ( 0 != iret )  {
        return 5;
    }

    /**/
    mctx.qctx = qctx;
    mctx.uiofd = uiofd;
    pregs = mmap( NULL, 0x1000, (PROT_READ | PROT_WRITE), MAP_SHARED, uiofd, 0 );
    if ( MAP_FAILED == pregs )  {
        return 6;
    }

    mctx.pctbase = (uintptr_t)pregs;


    /**/
    pevent = malloc( 5 * sizeof(struct epoll_event) );
    memset( pevent, 0, 5 * sizeof(struct epoll_event) );

    while( 1 )  {

        // printf( "wait, again\r\n" );
        num = epoll_wait( epfd, pevent, 5, 500 );
        
        if ( num < 0 )  {
            /* epoll error. */
            return 20;
        }
        
        if ( num == 0 )  {
            /* time out */
            // mthrd_pump_data( pctx );
            continue;
        }
        
        for ( int i=0; i<num; i++ )  {
            
            if ( pevent[i].data.fd == aqfd )  {
                
                iret = mthrd_proc_cmd( &mctx );
                if ( iret != 0 )  {
                    printf( "proc cmd fail...\n" );
                }

            } else if ( pevent[i].data.fd == uiofd )  {

                mthrd_proc_uio( uiofd );

            } else {
                printf( "epoll error fd\n" );
            }
        }
    }

    return 0;
}


